﻿using ExportTestCaseForTfs2012.Class;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.TestManagement.Client;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Windows.Forms;
using Microsoft.Office.Interop;

namespace ExportTestCaseForTfs2012
{
    /// <summary>
    /// Class permit to define Index
    /// </summary>
    public partial class Index : Form
    {
        #region Members

        /// <summary>
        /// The _TFS
        /// </summary>
        private TfsTeamProjectCollection tfsTeamProjectCollection;

        /// <summary>
        /// The _team project
        /// </summary>
        private ITestManagementTeamProject teamProject;

        /// <summary>
        /// The testPlans
        /// </summary>
        private ITestPlanCollection testPlans;

        /// <summary>
        /// The test suites
        /// </summary>
        private ITestSuiteEntryCollection testSuites;

        /// <summary>
        /// The test cases
        /// </summary>
        private ITestCaseCollection testCases;

        /// <summary>
        /// The suite
        /// </summary>
        private ITestSuiteEntry suite;

        /// <summary>
        /// The results
        /// </summary>
        private static Dictionary<Key, string> results = new Dictionary<Key, string>();

        /// <summary>
        /// The flags
        /// </summary>
        int flag1 = 0, flag2 = 0, flag3 = 0, flag4 = 0, flag5 = 0;

        #endregion Members

        #region Delegate

        /// <summary>
        /// Delegate
        /// </summary>
        private delegate void Execute();
        #endregion Delegate

        #region Ctor
        
        /// <summary>
        /// Initializes a new instance of the <see cref="Index"/> class.
        /// </summary>
        public Index()
        {
            InitializeComponent();
        }
        #endregion

        #region Methods

        #region Actions

        /// <summary>
        /// Handles the Click event of the BtnTeamProject control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void BtnTeamProject_Click(object sender, EventArgs e)
        {
            //Displaying the Team Project selection dialog to select the desired team project.
            TeamProjectPicker tpp = new TeamProjectPicker(TeamProjectPickerMode.SingleProject, false);
            tpp.ShowDialog();

            //Following actions will be executed only if a team project is selected in the the opened dialog.
            if (tpp.SelectedTeamProjectCollection != null)
            {
                this.tfsTeamProjectCollection = tpp.SelectedTeamProjectCollection;
                ITestManagementService testService = (ITestManagementService)tfsTeamProjectCollection.GetService(typeof(ITestManagementService));
                this.teamProject = testService.GetTeamProject(tpp.SelectedProjects[0].Name);

                //Populating the text field Team Project name (txtTeamProject) with the name of the selected team project.
                txtTeamProject.Text = tpp.SelectedProjects[0].Name;
                flag1 = 1;

                //Call to method "Get_TestPlans" to get the test testPlans in the selected team project
                GetTestPlans(teamProject);
            }
        }

        /// <summary>
        /// Handles the SelectedIndexChanged event of the ComBoxTestPlan control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        ///<remarks>Following method is invoked whenever a Test Plan is selected in the dropdown list.</remarks>
        ///<remarks>Acording to the selected Test Plan in the dropdown list the Test Suites present in the selected Test Plan are populated in the Test Suite selection dropdown.
        private void ComBoxTestPlan_SelectedIndexChanged(object sender, EventArgs e)
        {
            int i = -1;
            this.Cursor = Cursors.WaitCursor;
            comBoxTestSuite.Items.Clear();
            if (comBoxTestPlan.SelectedIndex >= 0)
            {
                i = comBoxTestPlan.SelectedIndex;
                this.testSuites = testPlans[i].RootSuite.Entries;
                GetTestSuites(testSuites);
                this.Cursor = Cursors.Arrow;
                flag2 = 1;
            }
        }

        /// <summary>
        /// Handles the Click event of the btnFolderBrowse control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void btnFolderBrowse_Click(object sender, EventArgs e)
        {
            folderBrowserDialog.ShowDialog();
            txtSaveFolder.Text = folderBrowserDialog.SelectedPath;
            if (txtSaveFolder.Text != null || txtSaveFolder.Text != string.Empty)
            {
                flag4 = 1;
            }
        }

        /// <summary>
        /// Handles the SelectedIndexChanged event of the comBoxTestSuite control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void ComBoxTestSuite_SelectedIndexChanged(object sender, EventArgs e)
        {
            int j = -1;
            if (comBoxTestPlan.SelectedIndex >= 0)
            {
                j = comBoxTestSuite.SelectedIndex;
                this.suite = testSuites[j].TestSuite.TestSuiteEntry;
                IStaticTestSuite suite1 = suite.TestSuite as IStaticTestSuite;
                GetTestCases(suite1);
                flag3 = 1;
            }
        }

        /// <summary>
        /// Handles the Click event of the btnExport control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void btnExport_Click(object sender, EventArgs e)
        {
            if (txtSaveFolder.Text != null || txtSaveFolder.Text != string.Empty)
            {
                flag5 = 1;
            }
            if (flag1 == 1 && flag2 == 1 && flag3 == 1 && flag4 == 1 && flag5 == 1)
            {
                this.Cursor = Cursors.WaitCursor;
                comBoxTestPlan.Enabled = false;
                comBoxTestSuite.Enabled = false;

                Microsoft.Office.Interop.Excel.Application xlApp;
                Microsoft.Office.Interop.Excel.Workbook xlWorkBook;
                Microsoft.Office.Interop.Excel.Worksheet xlWorkSheet;
                object misValue = System.Reflection.Missing.Value;
                Microsoft.Office.Interop.Excel.Range chartRange;

                xlApp = new Microsoft.Office.Interop.Excel.Application();
                xlWorkBook = xlApp.Workbooks.Add(misValue);
                xlWorkSheet = (Microsoft.Office.Interop.Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
                xlWorkSheet.Name = "Test Script";

                xlWorkSheet.Cells[1, 1] = "Test Case";
                xlWorkSheet.Cells[1, 2] = "Steps";
                xlWorkSheet.Cells[1, 3] = "";
                xlWorkSheet.Cells[1, 4] = "Expected Result";
                xlWorkSheet.Cells[1, 5] = "";
                xlWorkSheet.Cells[1, 6] = "Final Result";
                xlWorkSheet.Cells[1, 7] = "Summary";

                (xlWorkSheet.Columns["A", Type.Missing]).ColumnWidth = 75;
                (xlWorkSheet.Columns["B", Type.Missing]).ColumnWidth = 50;
                (xlWorkSheet.Columns["C", Type.Missing]).ColumnWidth = 15;
                (xlWorkSheet.Columns["D", Type.Missing]).ColumnWidth = 50;
                (xlWorkSheet.Columns["E", Type.Missing]).ColumnWidth = 50;
                (xlWorkSheet.Columns["F", Type.Missing]).ColumnWidth = 15;
                (xlWorkSheet.Columns["G", Type.Missing]).ColumnWidth = 20;

                int row = 2;
                int col = 1;
                string upperBound = "a";
                string lowerBound = "a";
                string upperBound2 = "f";
                string lowerBound2 = "f";
                string upperBound3 = "h";
                string lowerBound3 = "h";

                foreach (ITestCase testCase in testCases)
                {
                    upperBound = "a";
                    lowerBound = "a";
                    upperBound2 = "f";
                    lowerBound2 = "f";
                    upperBound3 = "h";
                    lowerBound3 = "h";
                    col = 1;

                    upperBound += row;
                    upperBound2 += row;
                    upperBound3 += row;

                    TestActionCollection testActions = testCase.Actions;
                    foreach (ITestStep testStep in testActions)
                    {
                        col = 2;
                        xlWorkSheet.Cells[row, 2] = testStep.Title.ToString();


                        xlWorkSheet.Cells[row, 4] = testStep.ExpectedResult.ToString();

                        row++;
                    }

                    lowerBound += (row - 1);
                    lowerBound2 += (row - 1);
                    lowerBound3 += (row - 1);

                    xlWorkSheet.get_Range(upperBound, lowerBound).Merge(false);
                    xlWorkSheet.get_Range(upperBound3, lowerBound3).Merge(false);

                    chartRange = xlWorkSheet.get_Range(upperBound, lowerBound);
                    chartRange.FormulaR1C1 = testCase.Title.ToString();

                    chartRange.HorizontalAlignment = 3;
                    chartRange.VerticalAlignment = 1;

                    if (results.Keys.Count(x => x.TestCase == testCase.Id.ToString()) > 0)
                    {
                        if (results != null && results.Count > 0)
                        {
                            var resultTarget = results.Where(x => x.Key.TestCase == testCase.Id.ToString()).First().Value.ToString();
                            if (!string.IsNullOrEmpty(resultTarget))
                            {
                                xlWorkSheet.Cells[row - 1, 6] = resultTarget;
                                xlWorkSheet.Cells[row - 1, 7] = testCase.CustomFields["Description"].Value.ToString();
                            }
                        }
                    }
                }

                lowerBound = "g";
                lowerBound += (row - 1);
                chartRange = xlWorkSheet.get_Range("a1", "g1");
                chartRange.Font.Bold = true;
                chartRange.Interior.Color = 18018418;

                chartRange = xlWorkSheet.get_Range("a1", lowerBound);
                chartRange.Cells.WrapText = true;

                chartRange.BorderAround(Microsoft.Office.Interop.Excel.XlLineStyle.xlContinuous,
                                        Microsoft.Office.Interop.Excel.XlBorderWeight.xlMedium,
                                        Microsoft.Office.Interop.Excel.XlColorIndex.xlColorIndexAutomatic, 
                                        Microsoft.Office.Interop.Excel.XlColorIndex.xlColorIndexAutomatic);
                try
                {

                    xlWorkBook.SaveAs(txtSaveFolder.Text + "\\" + textBoxNameFile.Text + ".xls", 
                        Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue,
                        Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
                    xlWorkBook.Close(true, misValue, misValue);
                    xlApp.Quit();

                    releaseObject(xlApp);
                    releaseObject(xlWorkBook);
                    releaseObject(xlWorkSheet);
                    this.Cursor = Cursors.Arrow;
                    comBoxTestPlan.Enabled = true;
                    comBoxTestSuite.Enabled = true;
                    MessageBox.Show("Test Cases exported successfully to specified file.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);

                    txtTeamProject.Text = string.Empty;
                    comBoxTestPlan.Items.Clear();
                    comBoxTestSuite.Items.Clear();

                    txtSaveFolder.Text = string.Empty;
                    flag1 = flag2 = flag3 = flag4 = flag5 = 0;
                }
                catch (Exception ex)
                {
                    if (ex.Message == "Cannot access '" + txtSaveFolder.Text + ".xls'.")
                    {
                        MessageBox.Show("File exists in specified location", "File Exists", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                        txtSaveFolder.Text = string.Empty;
                        flag5 = 0;
                    }

                    MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }
        

        #endregion

        #region InitializeMethods

        /// <summary>
        /// Gets the test testPlans.
        /// </summary>
        /// <param name="teamProject">The team project.</param>
        private void GetTestPlans(ITestManagementTeamProject teamProject)
        {
            //Getting all the test testPlans in the collection "testPlans" using the query.
            this.testPlans = teamProject.TestPlans.Query("Select * From TestPlan");

            foreach (ITestPlan item in this.testPlans)
            {
                CountAllTestRunsWithTestSuites(item.Id);
            }

            comBoxTestPlan.Items.Clear();
            flag2 = 0;
            comBoxTestSuite.Items.Clear();
            flag3 = 0;
            foreach (ITestPlan plan in testPlans)
            {
                //Populating the plan selection dropdown list with the name of Test Plans in the selected team project.
                comBoxTestPlan.Items.Add(plan.Name);
            }
        }

        /// <summary>
        /// Gets the test suites.
        /// </summary>
        /// <param name="Suites">The suites.</param>
        private void GetTestSuites(ITestSuiteEntryCollection Suites)
        {
            foreach (ITestSuiteEntry suite_entry in Suites)
            {
                this.suite = suite_entry;
                IStaticTestSuite newSuite = suite_entry.TestSuite as IStaticTestSuite;
                comBoxTestSuite.Items.Add(newSuite.Title);
            }
        }

        /// <summary>
        /// Gets the test cases.
        /// </summary>
        /// <param name="testSuite">The test suite.</param>
        private void GetTestCases(IStaticTestSuite testSuite)
        {
            this.testCases = testSuite.AllTestCases;
        }

        /// <summary>
        /// Counts all test runs with test suites.
        /// </summary>
        /// <param name="testPlanID">The test plan identifier.</param>
        private void CountAllTestRunsWithTestSuites(int testPlanID)
        {
            try
            {
                int fail = 0, pass = 0, other = 0, blocked = 0, active = 0, testCaseNumber = 0;
                ITestSuiteCollection testSuits = teamProject.TestSuites.Query("Select * from TestSuite where PlanId = " + testPlanID.ToString());
                string consult = "select * from TestResult where TestPlanId = " + testPlanID;
                ITestCaseResultCollection tcrcol = teamProject.TestResults.Query(consult);

                for (int i = 0; i < testSuits.Count; i++)
                {
                    ITestSuiteBase ts = testSuits[i];
                    foreach (ITestSuiteEntry tc in ts.TestCases)
                    {

                        IEnumerable<ITestCaseResult> testResult = tcrcol
                        .Where(testcase => testcase.TestCaseId == tc.TestCase.Id)
                        .GroupBy(result => result.TestConfigurationId)
                        .Select(result => result.OrderByDescending(topresult => topresult.LastUpdated).First());

                        if (testResult.LastOrDefault<ITestCaseResult>() != null)
                        {
                            foreach (ITestCaseResult tr in testResult)
                            {
                                testCaseNumber++;
                                var key = new Key { Suite = ts.Id.ToString(), TestCase = tc.Id.ToString() };
                                results.Add(key, tr.Outcome.ToString());
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        /// <summary>
        /// Releases the object.
        /// </summary>
        /// <param name="obj">The object.</param>
        private void releaseObject(object obj)
        {
            try
            {
                System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
                obj = null;
            }
            catch (Exception ex)
            {
                obj = null;
                MessageBox.Show("Unable to release the Object " + ex.ToString());
            }
            finally
            {
                GC.Collect();
            }
        }
        #endregion

        #endregion
    }
}
